import 'package:bloc/bloc.dart';
import 'package:mobile_app.core/core/domain/utils/either_extension.dart';
import 'package:mobile_app.core/core/domain/utils/with_previous_stream.dart';
import 'package:mobile_app.core/learning_content/application/bloc/bloc.dart';
import 'package:mobile_app.core/overlay/application/bloc/bloc.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/entities/custom_lexical_item_input.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/add_custom_lexical_item_use_case_input/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/create_custom_lexical_item/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/delete_custom_lexical_item_use_case_input/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/get_initial_data/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/update_custom_lexical_item_input_title/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/update_custom_lexical_item_input_transcription/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/update_custom_lexical_item_input_translation/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/update_custom_lexical_item_use_case_input_example/use_case.dart';
import 'package:mobile_app.home.collections/custom_lexical_item_creation_page/domain/use_cases/update_custom_lexical_item_use_case_input_translation/use_case.dart';

part 'bloc_state.dart';

class CustomLexicalItemCreationPageBloc extends Cubit<CustomLexicalItemCreationPageBlocState> {
  CustomLexicalItemCreationPageBloc({
    required String customCollectionId,
    required String lexicalItemTitle,
    required String lexicalItemTranslation,
    required LearningContentBloc learningContentBloc,
    required OverlayBloc overlayBloc,
    required GetInitialData getInitialData,
    required AddCustomLexicalItemUseCaseInput addCustomLexicalItemUseCaseInput,
    required CreateCustomLexicalItem createCustomLexicalItem,
    required DeleteCustomLexicalItemUseCaseInput deleteCustomLexicalItemUseCaseInput,
    required UpdateCustomLexicalItemInputTitle updateCustomLexicalItemInputTitle,
    required UpdateCustomLexicalItemInputTranscription updateCustomLexicalItemInputTranscription,
    required UpdateCustomLexicalItemInputTranslation updateCustomLexicalItemInputTranslation,
    required UpdateCustomLexicalItemUseCaseInputExample updateCustomLexicalItemUseCaseInputExample,
    required UpdateCustomLexicalItemUseCaseInputTranslation
        updateCustomLexicalItemUseCaseInputTranslation,
  })  : _customCollectionId = customCollectionId,
        _learningContentBloc = learningContentBloc,
        _overlayBloc = overlayBloc,
        _addCustomLexicalItemUseCaseInput = addCustomLexicalItemUseCaseInput,
        _createCustomLexicalItem = createCustomLexicalItem,
        _deleteCustomLexicalItemUseCaseInput = deleteCustomLexicalItemUseCaseInput,
        _updateCustomLexicalItemInputTitle = updateCustomLexicalItemInputTitle,
        _updateCustomLexicalItemInputTranscription = updateCustomLexicalItemInputTranscription,
        _updateCustomLexicalItemInputTranslation = updateCustomLexicalItemInputTranslation,
        _updateCustomLexicalItemUseCaseInputExample = updateCustomLexicalItemUseCaseInputExample,
        _updateCustomLexicalItemUseCaseInputTranslation =
            updateCustomLexicalItemUseCaseInputTranslation,
        super(_getInitialState(
          lexicalItemTitle: lexicalItemTitle,
          lexicalItemTranslation: lexicalItemTranslation,
          getInitialData: getInitialData,
        )) {
    streamWithPrevious = stream.withPreviousSeeded(state);
  }

  final String _customCollectionId;
  final LearningContentBloc _learningContentBloc;
  final OverlayBloc _overlayBloc;

  final AddCustomLexicalItemUseCaseInput _addCustomLexicalItemUseCaseInput;
  final CreateCustomLexicalItem _createCustomLexicalItem;
  final DeleteCustomLexicalItemUseCaseInput _deleteCustomLexicalItemUseCaseInput;
  final UpdateCustomLexicalItemInputTitle _updateCustomLexicalItemInputTitle;
  final UpdateCustomLexicalItemInputTranscription _updateCustomLexicalItemInputTranscription;
  final UpdateCustomLexicalItemInputTranslation _updateCustomLexicalItemInputTranslation;
  final UpdateCustomLexicalItemUseCaseInputExample _updateCustomLexicalItemUseCaseInputExample;
  final UpdateCustomLexicalItemUseCaseInputTranslation
      _updateCustomLexicalItemUseCaseInputTranslation;

  late final Stream<
          (CustomLexicalItemCreationPageBlocState, CustomLexicalItemCreationPageBlocState)>
      streamWithPrevious;

  static CustomLexicalItemCreationPageBlocState _getInitialState({
    required String lexicalItemTitle,
    required String lexicalItemTranslation,
    required GetInitialData getInitialData,
  }) {
    final result = getInitialData(
      lexicalItemTitle: lexicalItemTitle,
      lexicalItemTranslation: lexicalItemTranslation,
    );

    return CustomLexicalItemCreationPageBlocState(
      customLexicalItemInput: result.customLexicalItemInput,
    );
  }

  void requestCustomLexicalItemUseCaseInputAddition() {
    final result = _addCustomLexicalItemUseCaseInput(
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemUseCaseInputDeletion({
    required String useCaseInputId,
  }) {
    final result = _deleteCustomLexicalItemUseCaseInput(
      useCaseInputId: useCaseInputId,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemInputTitleUpdate({
    required String customLexicalItemInputTitle,
  }) {
    final result = _updateCustomLexicalItemInputTitle(
      customLexicalItemInputTitle: customLexicalItemInputTitle,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemInputTranscriptionUpdate({
    required String customLexicalItemInputTranscription,
  }) {
    final result = _updateCustomLexicalItemInputTranscription(
      customLexicalItemInputTranscription: customLexicalItemInputTranscription,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemInputTranslationUpdate({
    required String customLexicalItemInputTranslation,
  }) {
    final result = _updateCustomLexicalItemInputTranslation(
      customLexicalItemInputTranslation: customLexicalItemInputTranslation,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemInputUseCaseExampleUpdate({
    required String useCaseInputExample,
    required String useCaseInputId,
  }) {
    final result = _updateCustomLexicalItemUseCaseInputExample(
      useCaseInputExample: useCaseInputExample,
      useCaseInputId: useCaseInputId,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemInputUseCaseTranslationUpdate({
    required String useCaseInputTranslation,
    required String useCaseInputId,
  }) {
    final result = _updateCustomLexicalItemUseCaseInputTranslation(
      useCaseInputTranslation: useCaseInputTranslation,
      useCaseInputId: useCaseInputId,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    emit(state.copyWith(
      customLexicalItemInput: () => result.customLexicalItemInput,
    ));
  }

  void requestCustomLexicalItemCreation() {
    final failureOrResult = _createCustomLexicalItem(
      customCollectionId: _customCollectionId,
      collectionListItems: _learningContentBloc.state!.collectionListItems,
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
      customLexicalItemInput: state.customLexicalItemInput,
    );

    if (failureOrResult.isLeft()) {
      final failure = failureOrResult.asLeft();

      switch (failure) {
        case InvalidCustomLexicalItemCreationFailure():
          emit(state.copyWith(
            submittedCustomLexicalItemInputInvalid: () => true,
          ));

        case DuplicatedCustomLexicalItemCreationFailure():
          emit(state.copyWith(
            duplicatedCustomLexicalItemErrorShown: () => true,
          ));
      }

      return;
    }

    final result = failureOrResult.asRight();

    emit(state.copyWith(
      customLexicalItemCreated: () => true,
    ));

    _overlayBloc.showSuccessIndicator();

    _learningContentBloc.updateWith(
      lexicalItemMap: () => result.lexicalItemMap,
      collectionListItems: () => result.collectionListItems,
    );
  }
}
